#include "StdAfx.h"
#include "MediaFrame.h"
#include "fmtdefine.h"


CMediaFrame::CMediaFrame()
	:	m_fEOS(FALSE)
	,	m_llStart(0),m_llStop(0)
{	
}

BOOL CMediaFrame::GetEOS()
{
	return m_fEOS;
}

VOID CMediaFrame::SetEOS(BOOL fEos /* = TRUE */)
{
	m_fEOS = fEos;
}

EMediaType CMediaFrame::GetType()
{
	return MEDIA_TYPE_UNKNOW;
}


BOOL CMediaFrame::GetTime(LONGLONG& llStart, LONGLONG &llStop)
{
	llStart = m_llStart;
	llStop  = m_llStop;
	return TRUE;
}

BOOL CMediaFrame::SetTime(LONGLONG llStart, LONGLONG llStop)
{
	m_llStart = llStart;
	m_llStop  = llStop;

	return TRUE;
}

BOOL CMediaFrame::Copy(IMediaSample* pSample, AM_MEDIA_TYPE* pmt)
{
	if(!pSample || !pmt) return FALSE;
	if(FAILED(pSample->GetTime(&m_llStart, &m_llStop))) return FALSE;	
	return TRUE;
}


/////////////////////////////////////////////////////////////

CVideoFrame::CVideoFrame()
:m_fmt(PIX_FMT_NONE),m_w(0),m_h(0),m_pFrame(NULL), m_pBufferUvChange(NULL)
{
	m_dataSize = 0;
}


CVideoFrame::~CVideoFrame()
{
	if(m_pBufferUvChange){
		av_free((void*)m_pBufferUvChange);
	}
	free_picture();
}

EMediaType CVideoFrame::GetType()
{
	return MEDIA_TYPE_VIDEO;
}

EMediaType CAudioFrame::GetType()
{
	return MEDIA_TYPE_AUDIO;
}

AVFrame* CVideoFrame::alloc_picture(PixelFormat fmt, int w, int h)
{	
	AVFrame * pFrame = avcodec_alloc_frame();
	if(!pFrame) return NULL;
	m_dataSize = avpicture_get_size(fmt, w, h);
	uint8_t* pbuf = (uint8_t*)av_malloc(m_dataSize);
	if(!pbuf){
		av_free(pFrame);
		return NULL;
	}
	avpicture_fill((AVPicture*)pFrame, pbuf, fmt, w, h);
	return pFrame;
}

VOID CVideoFrame::free_picture()
{
	if(m_pFrame){
		if(m_pFrame->data[0]) av_free(m_pFrame->data[0]);
		av_free(m_pFrame);
		m_pFrame = NULL;
	}	
	m_dataSize = 0;
}


BOOL CVideoFrame::GetFormat(PixelFormat &fmt, int& w, int& h)
{
	fmt = m_fmt;
	w = m_w;
	h = m_h;
	return TRUE;
}

BOOL CVideoFrame::SetFormat(PixelFormat fmt, int w, int h)
{
	if(m_pFrame)free_picture();
	m_pFrame = alloc_picture(fmt, w, h);
	if(!m_pFrame) return FALSE;
	m_fmt = fmt;
	m_w = w;
	m_h = h;
	return TRUE;

}


AVFrame* CVideoFrame::GetAVFrame()
{
	return m_pFrame;
}

BOOL CVideoFrame::Copy(IMediaSample* pSample, AM_MEDIA_TYPE* pmt)
{	
	if( !CMediaFrame::Copy(pSample, pmt) )return FALSE;

	PixelFormat fmt;
	int w, h;
	if(!VideoAM2FM(pmt, fmt, w, h)){
		return FALSE;
	}else{
		if(fmt != m_fmt || w != m_w || h != m_h){
			SetFormat(fmt, w, h);
		}
	}
	ASSERT(m_pFrame);

	BYTE * pData = NULL;
	long size = 0;
	HRESULT hr = S_OK;
	size = pSample->GetActualDataLength();
	if(size == 0 || size != m_dataSize) return FALSE;
	
	hr = pSample->GetPointer(&pData);
	if(FAILED(hr))  return FALSE;
	if(pmt->subtype == MEDIASUBTYPE_YV12) {
		int size1, size2 , w2, h2;
		size1 = m_w * m_h;		
		w2 = (m_w + (1 << 1) - 1) >> 1;
		h2 = (m_h + (1 << 1) - 1) >> 1;
		size2 = w2 * h2;
		memcpy(m_pFrame->data[0], pData, (size_t)size1);
		memcpy(m_pFrame->data[1], pData + size1 + size2, (size_t)size2);
		memcpy(m_pFrame->data[2], pData + size1, (size_t)size2);
	}else{
		memcpy(m_pFrame->data[0], pData, (size_t)size);
	}


	
	
	return TRUE;

}


BOOL CVideoFrame::ChangeUVOrder()
{

	if(!m_pFrame ) return FALSE;
	unsigned int uvsize = (unsigned int)(m_pFrame->data[2] - m_pFrame->data[1]);
	if(!m_pBufferUvChange){		
		m_pBufferUvChange = (uint8_t*)av_malloc(uvsize);
	}
	memcpy((void*)m_pBufferUvChange, (void*)m_pFrame->data[1], uvsize);
	memcpy((void*)m_pFrame->data[1], (void*)m_pFrame->data[2], uvsize);
	memcpy((void*)m_pFrame->data[2], (void*)m_pBufferUvChange, uvsize);

	//BYTE* p = m_pFrame->data[1];
	//m_pFrame->data[1] = m_pFrame->data[2];
	//m_pFrame->data[2] = p;

	//int ls = m_pFrame->linesize[1];
	//m_pFrame->linesize[1] = m_pFrame->linesize[2];
	//m_pFrame->linesize[2] = ls;

	return TRUE;	
}



///////////////////

CAudioFrame::CAudioFrame()
	:	m_nDataSize(0)
	,	m_pData(NULL)
	,	m_nSamplesPerSec(0)
	,	m_nChannels(0)
	,	m_nBufferSize(0)
{
}

CAudioFrame::~CAudioFrame()
{
	if(m_pData){
		av_free(m_pData);
	}
}

BOOL CAudioFrame::Copy(IMediaSample* pSample, AM_MEDIA_TYPE* pmt)
{
	if(!CMediaFrame::Copy(pSample, pmt))return FALSE;

	if(!pSample || !pmt ) return FALSE;
	if(!AudioAM2FM(pmt, m_nChannels, m_nSamplesPerSec))
		return FALSE;
	if(!m_pData)InitDefaultBuffer();

	//ASSERT(m_nDataSize >= m_nBufferSize);
	m_nDataSize = pSample->GetActualDataLength();
	if(m_nDataSize == 0) return FALSE;
	m_nSampleCount = m_nDataSize / (m_nChannels * 2);	
	BYTE* pdata = NULL;
	if(FAILED(pSample->GetPointer(&pdata)))
		return FALSE;
	memcpy(m_pData, pdata, m_nDataSize);
	return TRUE;
}

void CAudioFrame::SetDataSize(int size)
{
	m_nDataSize = size;
}

BOOL CAudioFrame::GetFormat(int &Channels, int& sampleRate)
{
	Channels = m_nChannels;
	sampleRate = m_nSamplesPerSec;
	return TRUE;
}

BOOL CAudioFrame::SetFormat(int Channels, int sampleRate)
{
	m_nChannels = Channels;
	m_nSamplesPerSec = sampleRate;
	return TRUE;
}

BOOL CAudioFrame::SetSampleCount(int sc)
{
	m_nSampleCount = sc;
	m_nDataSize = m_nSampleCount * m_nChannels * 2;
	return TRUE;
}

int CAudioFrame::GetSampleCount()
{
	return m_nSampleCount;
}

BOOL CAudioFrame::InitDefaultBuffer()
{
	if(m_pData) {
		av_free(m_pData);
		m_pData = NULL;
	}
	m_nBufferSize = 48000*2*2*2;
	m_pData = (short*)av_malloc(m_nBufferSize);//48000Hz, 2ch, short, 2mins
	if(!m_pData) return FALSE;
	return TRUE;
}

